#include "ThreadPool.h"
#include <core/system/cpu_info.h>
#include <QTimer>

#ifdef WIN32
#include <process.h>
#endif

namespace qb{
	namespace ht{
        CThreadProcess::CThreadProcess()
            : m_msWait(200)
            , m_is_idle(true)
        {
            moveToThread(this);
        }

        void CThreadProcess::start()
        {
            QThread::start();
        }

        void CThreadProcess::run()
        {
            QTimer* timer = new QTimer(this);
            connect(timer, SIGNAL(timeout()), this, SLOT(onTimer()), Qt::UniqueConnection);
            timer->setInterval(m_msWait);
            timer->start();

            exec();

            timer->stop();
            timer = NULL;
        }

        void CThreadProcess::stop()
        {
            quit();
            wait();
        }

        void CThreadProcess::AddTask(pTaskFunc task, void* param)
        {
            ScopedLock scoped(m_lock);
            m_tasks.push_back(TaskItem(task, param));
        }

        bool CThreadProcess::GetTask(TaskItem& task)
        {
            ScopedLock scoped(m_lock);
            if (m_tasks.size() > 0)
            {
                task = m_tasks.at(0);
                m_tasks.erase(m_tasks.begin());
                return true;
            }
            return false;
        }

        int CThreadProcess::GetTaskCount()
        {
            ScopedLock scoped(m_lock);
            return m_tasks.size();
        }

        void CThreadProcess::SetWaitTime(unsigned long waitTime)
        {
            ScopedLock scoped(m_lock);
            m_msWait = waitTime;
        }

        void CThreadProcess::CallTask(pTaskFunc task, void* param)
        {
            m_is_idle = false;
#ifdef WIN32
            __try{
#else
            try {
#endif
                task(param);
            }
#ifdef WIN32
            __except (1)
#else
            catch (...)
#endif
            {
                m_is_idle = true;
            }
            m_is_idle = true;
        }

        void CThreadProcess::onTimer()
        {
            TaskItem item;
            while (GetTask(item))
            {
                CallTask(item.proc, item.param);
            }
        }

        CTaskThread::CTaskThread()
        {
            m_process = new CThreadProcess();
            m_process->start();
        }

        void CTaskThread::AddTask(pTaskFunc task, void* param)
        {
            if (!m_process)
            {
                return;
            }

            m_process->AddTask(task, param);
        }

        bool CTaskThread::isidle()
        {
            if (!m_process)
            {
                return false;
            }

            return m_process->isidle();
        }

        void CTaskThread::SetWaitTime(unsigned long waitTime)
        {
            if (!m_process)
            {
                return;
            }

            m_process->SetWaitTime(waitTime);
        }

        void CTaskThread::Close()
        {
            if (!m_process)
            {
                return;
            }

            m_process->stop();
            delete m_process;
            m_process = nullptr;
        }

		////////////////////////////////////////////////////////////////////////////////
		ThreadPool* ThreadPool::instance_ = NULL;
		ThreadPool* ThreadPool::GetInstance()
		{
			static FastLock lock;
			if (instance_ == NULL)
			{
				ScopedLock scoped(lock);
				if (instance_ == NULL)
				{
					instance_ = new ThreadPool();
				}
			}
			return instance_;
		}
		ThreadPool::ThreadPool(){
            int threadnum = qb::CpuInfo::DetectNumberOfCores();
			m_next_thread = 0;
			for (int i = 0; i < threadnum; i++)
			{
				m_threads.push_back(new CTaskThread());
			}
		}
		ThreadPool::~ThreadPool(){
			for (int i = 0; i < (int)m_threads.size(); i++)
			{
				CTaskThread* tt = m_threads.at(i);
				tt->Close();
			}
			m_threads.clear();
		}
		bool ThreadPool::PostTask(pTaskFunc task, void* param){

			// 循环挑选一个线程来执行该任务
			// 挑选一个空闲后台线程来执行当前任务，
			// 尝试threads。size()次后挑选忽略空闲状态
			int count = 0;
			while (true)
			{
				CTaskThread* tt = m_threads.at(m_next_thread);
				if (tt->isidle() || count >= (int)m_threads.size())
				{
					tt->AddTask(task, param);
					m_next_thread = (m_next_thread + 1) % (m_threads.size());
					break;
				}
				count++;
				m_next_thread = (m_next_thread + 1) % (m_threads.size());
			}

			return true;
		}
		void ThreadPool::ChangeMode(kThreadMode mode)
		{
            unsigned long waittime = mode == kThreadModeFast ? 1 : 200;
			for (int i = 0; i < (int)m_threads.size(); i++)
			{
				CTaskThread* thread = m_threads.at(i);
				thread->SetWaitTime(waittime);
			}
		}
	}//namespace ht
}//namespace qb
